const Order = require('../entity/product/order');
const TaskIncome = require('../entity/account/taskincome');
const CreditRecord = require('../entity/credit/creditrecord');
const AreaDelivery = require('../entity/area/areadelivery');
const CreditAmount = require('../entity/credit/creditamount');
const AdminUser = require('../entity/user/adminuser');
const ChargeAccount = require('../entity/charge/chargeaccount');

const userService = require('./user');
const productService = require('./productService');
const promoteService = require('./promoteService');
const creditServer = require('./creditService');
const chargeServer = require('./chargeService');

const { CommonServiceError } = require('../module/error/svcerror');

const { generateRandomOrderIdWithTime } = require('../module/tool/common');

const EnvelopeStatus = require('../module/const/EnvelopeStatus');
const ConsumerType = require('../module/const/ConsumerType');
const OrderStatus = require('../module/const/OrderStatus');
const { orderHasPayed } = require('./weixin/payment');

const timeTool = require('../module/tool/time');
const OrderVersion = require('../module/const/OrderVersion');
const PaymentType = require('../module/const/paymentType');
const CreditRecordStatus = require('../module/const/CreditRecordStatus');
const { orderRefund } = require('./payment/orderPaymet');
const ProductType = require('../module/const/ProductType');
const SecKillOrder = require('../entity/product/seckillorder');

const { getCurrentTimestamp } = require('../module/tool/time');

const {
    addPaymentOrderStatusListener,
    goodsBugPaymentSceneId,
    queryPaymentOrder,
    requestPaymentOrder,
    requestOrderRefund,
    refundSceneId
} = require('./payment-merchant');
const moment = require('moment');

// 消息队列
let hasPaymentOrderStatusListener = false;
if (!hasPaymentOrderStatusListener) {
    hasPaymentOrderStatusListener = true;
    addPaymentOrderStatusListener(goodsBugPaymentSceneId, async (paymentOrderId, paymentOrderStatus) => {
        const orderEntity = new Order();
        const orderModel = orderEntity.getModel();
        const orderData = await orderModel.findOne({
            paymentOrderId: paymentOrderId
        });
        if (!orderData) {
            return;
        }
        if (paymentOrderStatus === '3' && orderData.status === OrderStatus.Committed.value) {
            // 支付成功
            orderData.status = OrderStatus.Payed.value;
            orderData.payTime = getCurrentTimestamp();
            orderData.save();
        } else {
            await recoverUserAssert(orderData._id);
        }
    }).then(() => {
        console.log('addPaymentOrderStatusListener success');
    });
}

async function getOrderDataById (orderId) {
    const orderModel = new Order().getModel();
    return orderModel.findById(orderId);
}

// =========================== 前端接口 ===============================
// 订单结算 --已优化
async function orderSettlement (userId, areaId, cartItemIdList, envelopeId, coinCount) {
    const userInfo = await userService.getUserInfo(userId);
    if (userInfo.isPromoter && coinCount > 0) {
        throw new CommonServiceError('推广员无法使用金币！');
    }

    const cartInfo = await productService.assembleCartInfo(cartItemIdList);

    // 用户折后价格
    let originalPrice = 0;
    // 配送费
    let deliveryFee = 0;
    // 红包抵扣金额
    let envelopFee = 0;
    // 金币抵扣
    let coinFee = 0;
    // 信用金信息
    let creditInfo = { validCreditAmount: 0, creditAmount: 0, useCreditAmount: 0, isEnable: false };
    const CreditAmountModel = new CreditAmount().getModel();
    const creditAmountInfo = await CreditAmountModel.findOne({ userId, isEnable: true });
    if (creditAmountInfo) {
        creditInfo.isEnable = true;
        creditInfo.validCreditAmount = Math.round(creditAmountInfo.creditAmount * 100 - creditAmountInfo.useCreditAmount * 100);
        creditInfo.creditAmount = Math.round(creditAmountInfo.creditAmount * 100);
        creditInfo.useCreditAmount = Math.round(creditAmountInfo.useCreditAmount * 100);
    }

    // 1.计算折扣价
    const discount = userInfo.discount;
    const productList = [];
    let calculatePrice = 0;
    for await (const item of cartInfo) {
        // 判断库存
        if (item.productData.inventory < 1 || item.productData.inventory < item.skuInfo.inventory * item.cartInfo.count) {
            throw new CommonServiceError(`${item.productData.title}库存不足,请联系管理员补货！`);
        }

        const productItem = {
            // 产品信息
            productId: item.cartInfo.productId,
            image: item.productData.images[0],
            title: item.productData.title,
            // sku信息
            skuId: item.cartInfo.skuId,
            skuTitle: item.skuInfo.title,
            price: item.skuInfo.price,
            originalPrice: item.skuInfo.originalPrice,
            inventory: item.skuInfo.inventory,
            // 购买信息
            count: item.cartInfo.count,
            isSecKillPrice: item.cartInfo.isSecKillPrice,
            productType: item.productData.productType
        };

        // 普通产品
        if (item.productData.productType === ProductType.Ordinary) {
            calculatePrice += item.skuInfo.price * item.cartInfo.count;
        }
        // 秒杀产品
        if (item.productData.productType === ProductType.SecKill) {
            if (item.cartInfo.isSecKillPrice) {
                calculatePrice += item.skuInfo.price * item.cartInfo.count;
            } else {
                calculatePrice += item.skuInfo.originalPrice * item.cartInfo.count;
            }
        }
        productList.push(productItem);
    }
    calculatePrice = Math.round(calculatePrice);
    originalPrice = Math.round(calculatePrice * discount / 100);

    // 2.计算配送费
    const AreaDeliveryModel = new AreaDelivery().getModel();
    const deliveryFeeData = await AreaDeliveryModel.findOne({ areaId, isEnable: true });

    // 查询当天是否有付过配送费
    const OrderEntity = new Order();
    const orderModel = OrderEntity.getModel();
    // 查询当天是否有支付订单且有配送费
    const hasTodayOrder = await orderModel.exists({
        userId,
        areaId,
        deliveryFee: { $gt: 0 },
        status: OrderStatus.Payed.value,
        payTime: {
            $gte: moment().startOf('day').format('X'),
            $lt: moment().endOf('day').format('X')
        }
    });

    if (deliveryFeeData && originalPrice < deliveryFeeData.limitPrice && !hasTodayOrder) {
        // 计算价格小于免费配送起送价
        deliveryFee = deliveryFeeData.deliveryFee;
    }

    // 3.计算红包抵扣价格
    if (envelopeId) {
        const envelopInfo = await promoteService.getEnvelopeById(envelopeId);
        if (envelopInfo.status !== EnvelopeStatus.enable) {
            throw new CommonServiceError('红包已失效！');
        }
        if (originalPrice < envelopInfo.reachAmount) {
            throw new CommonServiceError('未达到红包满减金额！');
        }
        if (envelopInfo.userId.toString() !== userId) {
            throw new CommonServiceError('红包使用对象有误！');
        }
        envelopFee = envelopInfo.amount;
    }

    // 4.计算金币（金币的单位为：元）
    if (coinCount && coinCount > 0) {
        const accountInfo = await promoteService.getPromoteAccountByUserId(userId);
        if (accountInfo.coinCount < coinCount) {
            throw new CommonServiceError('金币不足！');
        }
        coinFee = coinCount * 100;
    }

    let finalPrice = originalPrice + deliveryFee - envelopFee;
    if (finalPrice <= coinFee) {
        // 最少支付1元
        finalPrice = 100;
        coinFee = finalPrice - 100;
    } else {
        finalPrice = finalPrice - coinFee;
    }

    // 5.钱包余额
    const chargeAccountEntity = new ChargeAccount();
    const chargeAccountModel = chargeAccountEntity.getModel();
    const chargeAccountData = await chargeAccountModel.findOne({
        userId,
        areaId
    });
    let walletBalance = 0;
    if (chargeAccountData) {
        walletBalance = chargeAccountData.totalAmount;
    }

    return {
        productList,
        discount,
        originalPrice,
        deliveryFee,
        envelopFee,
        coinFee,
        finalPrice,
        creditInfo,
        walletBalance
    };
}
// 提交订单 --已优化
async function submitOrder (userId, areaId, addressInfo, cartItemIdList, remark, envelopeId, coinCount, paymentMode) {
    // 计算最终订单价格
    const settlementInfo = await this.orderSettlement(userId, areaId, cartItemIdList, envelopeId, coinCount);

    // 判断信用金是否充足
    if (paymentMode === PaymentType.creditAmount && settlementInfo.creditInfo.validCreditAmount < settlementInfo.finalPrice) {
        throw new CommonServiceError('信用金额度不足，请联系管理员！');
    }

    // 创建订单
    const name = addressInfo.name;
    const phone = addressInfo.phone;
    const area = addressInfo.area;
    const detailedAddress = addressInfo.detailedAddress;
    const orderNo = generateRandomOrderIdWithTime();

    const OrderEntity = new Order();
    const orderModel = OrderEntity.getModel();
    const orderData = await OrderEntity.getDoc({
        areaId,
        userId,
        // 收货地址信息
        name,
        phone,
        area,
        detailedAddress,
        // 订单信息
        orderNo,
        productList: settlementInfo.productList,
        price: settlementInfo.finalPrice,
        discount: settlementInfo.discount,
        deliveryFee: settlementInfo.deliveryFee,
        envelopeId: envelopeId || null,
        envelopeFee: settlementInfo.envelopFee,
        coinCount: settlementInfo.coinFee / 100,
        status: OrderStatus.Committed.value,
        remark,
        paymentMode,
        version: OrderVersion.version
    }).save();

    // 微信下单
    let returnData = {};
    if (orderData.paymentMode === PaymentType.wxPay) {
        if (settlementInfo.finalPrice > 0) {
            try {
                const userInfo = await userService.getUserInfo(userId);
                const openid = userInfo.openid;
                const {
                    paySign,
                    orderId
                } = await requestPaymentOrder(goodsBugPaymentSceneId, openid, Math.round(settlementInfo.finalPrice), '大力蛮牛商品下单');
                orderData.paymentOrderId = orderId;
                returnData.paySign = paySign;
                returnData.orderId = orderData._id;
                orderData.save();
            } catch (e) {
                await orderModel.findByIdAndDelete(orderData._id);
                throw e;
            }
        } else {
            orderData.status = OrderStatus.Payed.value;
            orderData.payTime = timeTool.getCurrentTimestamp();
            await orderData.save();
        }
    }
    // 信用金支付
    if (orderData.paymentMode === PaymentType.creditAmount) {
        // 创建信用金使用记录，扣除信用金
        await creditServer.deductCreditAmount(orderData._id, userId, areaId, settlementInfo.finalPrice);

        // 订单设置为已支付
        orderData.status = OrderStatus.Payed.value;
        orderData.payTime = timeTool.getCurrentTimestamp();
        returnData.orderId = orderData._id;
        await orderData.save();
    }

    // 钱包余额支付
    if (orderData.paymentMode === PaymentType.balance) {
        // 创建余额使用记录，扣除余额
        await chargeServer.createChargeConsumeRecord(orderData._id);

        // 订单设置为已支付
        orderData.status = OrderStatus.Payed.value;
        orderData.payTime = timeTool.getCurrentTimestamp();
        returnData.orderId = orderData._id;
        await orderData.save();
    }
    // 1.使用红包
    if (envelopeId) {
        await promoteService.useEnvelop(envelopeId);
    }
    // 2.消费金币
    if (coinCount && coinCount > 0) {
        await promoteService.consumeCoin(userId, orderData._id, coinCount, ConsumerType.order, areaId);
    }
    // 3.扣减库存
    await productService.reduceInventory(settlementInfo.productList);
    // 4.加入秒杀记录订单
    await insertSecKillOrder(userId, areaId, orderData._id, settlementInfo.productList);
    // 5.生成推广收入
    await promoteService.generatePromoteIncome(orderData._id, settlementInfo.finalPrice, userId, areaId);

    // 删除购物车内容
    await productService.removeCartItem(cartItemIdList);

    return returnData;
}
// 校验订单支付状态 --已优化
async function checkOrderPaymentStatus (orderId) {
    const OrderModel = new Order().getModel();
    const orderData = await OrderModel.findById(orderId);

    // 只有微信支付情况才考虑
    if (orderData.paymentMode === PaymentType.wxPay) {
        const paymentOrderData = await queryPaymentOrder(orderData.paymentOrderId);
        if (paymentOrderData.status === '3' && orderData.status === OrderStatus.Committed.value) {
            // 支付成功
            orderData.status = OrderStatus.Payed.value;
            orderData.payTime = timeTool.getCurrentTimestamp();
            orderData.save();
        } else {
            await recoverUserAssert(orderId);
        }
    }

    return orderData;
}

// 小程序客户【取消未支付订单】 --已优化
async function cancelOrder (userId, orderId) {
    const orderData = await getOrderDataById(orderId);

    if (orderData.status !== OrderStatus.Committed.value) {
        throw new CommonServiceError('只能取消未支付的订单！');
    }

    // 订单设置为取消状态
    orderData.status = OrderStatus.Cancel.value;
    orderData.cancelTime = timeTool.getCurrentTimestamp();
    await orderData.save();

    // 回复用户资产
    await recoverUserAssert(orderId);

    return 1;
}

// 创建秒杀商品购买记录 --已优化
async function insertSecKillOrder (userId, areaId, orderId, productList) {
    const SecKillOrderEntity = new SecKillOrder();
    for await (const item of productList) {
        if (item.productType === ProductType.SecKill && item.isSecKillPrice) {
            await SecKillOrderEntity.getDoc({
                areaId,
                userId,
                orderId,
                productId: item.productId,
                skuId: item.skuId,
                price: item.price * item.count,
                count: item.count
            }).save();
        }
    }
    return 1;
}
// 删除秒杀产品购买记录
async function recoverSecKillOrder (orderId) {
    const SecKillOrderModel = new SecKillOrder().getModel();
    return SecKillOrderModel.findOneAndRemove({ orderId });
}
// 恢复用户资产 --已优化
async function recoverUserAssert (orderId) {
    const orderData = await getOrderDataById(orderId);
    // 1.退还红包
    if (orderData.envelopeId) {
        await promoteService.recoverEnvelop(orderData.envelopeId);
    }
    // 2.退还金币
    if (orderData.coinCount > 0) {
        await promoteService.recoverCoin(orderData._id);
    }
    // 3.退还库存
    await productService.increaseInventory(orderData._id);
    // 4.删除秒杀产品购买记录
    await recoverSecKillOrder(orderId);
    // 5.将推广收入设置为"已失效"
    await promoteService.recoverPromoteRecord(orderData._id);
}

// 小程序订单中心支付
async function orderCenterPayment (userId, _orderId) {
    const orderData = await getOrderDataById(_orderId);
    const userInfo = await userService.getUserInfo(userId);
    const openid = userInfo.openid;
    let returnData = {};
    const {
        paySign,
        orderId
    } = await requestPaymentOrder(goodsBugPaymentSceneId, openid, Math.round(orderData.price), '大力蛮牛商品下单');
    orderData.paymentOrderId = orderId;
    returnData.paySign = paySign;
    returnData.orderId = orderData._id;
    orderData.save();
    return returnData;
}

// 客户订单退款 --已废弃
async function refundOrder (userId, orderId, price, refundDescribe) {
    if (price > 0) {
        throw new CommonServiceError('如需退款请联系管理员！');
    }
    // 查询订单数据
    const orderData = await getOrderDataById(orderId);
    if (!orderData) {
        throw new CommonServiceError('不存在该订单');
    }
    if (orderData.price !== price) {
        throw new CommonServiceError('退款金额有误');
    }
    const CreditRecordModel = new CreditRecord().getModel();
    const creditRecordData = CreditRecordModel.findOne({ orderId });

    if (creditRecordData.status === CreditRecordStatus.repayment.value) {
        throw new CommonServiceError('订单已还款！');
    }

    if (orderData.price !== 0) {
        // 微信退款
        if (orderData.paymentMode === PaymentType.wxPay) {
            const res = orderHasPayed(orderId);
            if (!res) {
                throw new CommonServiceError('订单未付款，不可提交退款！');
            }
            orderData.refundId = await orderRefund(orderData.price, orderId, '大力蛮牛商品退款');
        }

        // 信用金退款
        if (orderData.paymentMode === PaymentType.creditAmount) {
            await creditServer.sendBackCreditAmount(userId, price, orderId);
        }
    }

    orderData.status = OrderStatus.Refund.value;
    orderData.refundTime = timeTool.getCurrentTimestamp();
    orderData.refundDescribe = refundDescribe;
    orderData.save();

    // 退还红包
    if (orderData.envelopeId) {
        await promoteService.recoverEnvelop(orderData.envelopeId);
    }
    // 退还金币
    if (orderData.coinCount > 0) {
        await promoteService.recoverCoin(orderData._id);
    }
    // 退还库存
    await productService.increaseInventory(orderData._id);
    // 将推广收入设置为"已失效"
    await promoteService.recoverPromoteRecord(orderData._id);
    return 1;
}

// =========================== 后台接口 ===============================
// 后台设置订单状态 --已优化
async function setOrderStatus (adminId, areaId, orderId, price, status) {
    status = parseInt(status);

    const orderModel = new Order().getModel();
    const orderData = await orderModel.findById(orderId);

    // 更新状态
    orderData.status = status;
    const time = timeTool.getCurrentTimestamp();

    // 配送中
    if (status === OrderStatus.Delivering.value) {
        orderData.deliveryTime = time;
    }
    // 已完成
    if (status === OrderStatus.Finished.value) {
        orderData.finishTime = time;

        // 微信支付
        if (orderData.paymentMode === PaymentType.wxPay) {
            // 校验是否完成支付
            let payStatus;
            if ('paymentOrderId' in orderData) {
                const paymentOrderData = await queryPaymentOrder(orderData.paymentOrderId);
                payStatus = paymentOrderData.status;
            } else {
                const hasPayed = await orderHasPayed(orderId);
                if (hasPayed) {
                    payStatus = '3';
                }
            }
            if (payStatus !== '3') {
                throw new CommonServiceError('订单未付款');
            }

            // 微信支付已完成才会增加收入
            const AdminUserModel = new AdminUser().getModel();
            const adminInfo = await AdminUserModel.findOne({ areaId });
            if (!adminInfo) {
                throw new CommonServiceError('未查询到管理员');
            }

            const TaskIncomeEntity = new TaskIncome();
            const TaskIncomeModel = TaskIncomeEntity.getModel();

            if (!await TaskIncomeModel.exists({
                adminId: adminInfo._id,
                areaId,
                orderId
            })) {
                await TaskIncomeEntity.getDoc({
                    adminId: adminInfo._id,
                    areaId,
                    price: orderData.price,
                    orderId
                }).save();
            }
        }

        // 增加积分
        await userService.addUserScore(orderData.userId, orderData.price / 100);
        // 结算推广记录
        await promoteService.settlementPromoteIncome(orderId);
    }

    orderData.save();
    return 1;
}
// 后台取消订单并退款 --已优化
async function cancelRefundOrder (orderId, userId, price, refundDescribe) {
    // 查询订单数据
    const orderData = await getOrderDataById(orderId);

    if (orderData.status === OrderStatus.Finished.value) {
        throw new CommonServiceError('已完成订单不能取消！');
    }
    if (!orderData) {
        throw new CommonServiceError('不存在该订单');
    }

    if (orderData.price > 0) {
        // 微信退款
        if (orderData.paymentMode === PaymentType.wxPay) {
            let payStatus;
            if ('paymentOrderId' in orderData) {
                const paymentOrderData = await queryPaymentOrder(orderData.paymentOrderId);
                payStatus = paymentOrderData.status;
            } else {
                const hasPayed = await orderHasPayed(orderId);
                if (hasPayed) {
                    payStatus = '3';
                }
            }
            if (payStatus !== '3') {
                throw new CommonServiceError('订单未付款，不可取消退款！');
            }

            const refundResult = await requestOrderRefund(refundSceneId, orderData.paymentOrderId, price, orderData.price
                , '大力蛮牛商品退款');
            orderData.refundOrderId = refundResult.orderId;
        }

        // 信用金退款
        if (orderData.paymentMode === PaymentType.creditAmount) {
            await creditServer.sendBackCreditAmount(userId, orderData.price, orderId);
        }

        // 余额退款
        if (orderData.paymentMode === PaymentType.balance) {
            await chargeServer.refundWalletBalance(orderId);
        }
    }

    orderData.status = OrderStatus.Refund.value;
    orderData.refundTime = timeTool.getCurrentTimestamp();
    orderData.refundDescribe = refundDescribe;
    orderData.save();

    // 退还库存
    await recoverUserAssert(orderId);
    return 1;
}

module.exports = {
    orderSettlement,
    submitOrder,
    checkOrderPaymentStatus,
    cancelOrder,
    refundOrder,
    setOrderStatus,
    cancelRefundOrder,
    getOrderDataById,
    orderCenterPayment
};
